package process;

import CPU.CPU;
import action.ProcessHistory;
import controller.ScheduiUIController;
import device.Device;
import device.DeviceDispatcher;
import javafx.animation.PathTransition;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.property.*;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.ProgressBarTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;
import memory.Memory;
import memory.MemoryDispatcher;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ProcessDispatcher {
    //    运行进程
    private Process runningProcess;
    public static volatile boolean isrunning = false;
    //    闲逛进程
    private static PCB hangOutProcess;
    //    程序寄存器
    private static PCB processRegister;
    //    结束进程list
    private static ObservableList<PCB> endProcessList;
    //    就绪进程list
    private static ObservableList<PCB> readyProcessList;
    //    阻塞进程list
    private static ObservableList<PCB> blockedProcessList;

    // 记录运行历史list
    private static ObservableList<ProcessHistory> processHistoryList;

    //    设备list
    private static ObservableList<Device> deviceList;
    //private final Thread dispatchThread;D
//    进程分配器
    private volatile static ProcessDispatcher processDispatcher;
    public static ScheduiUIController scheduiUIController;
    private static DeviceDispatcher DEVICE_DISPATCHER;
    private static Path pathrunToEnd;
    private static Path pathreadyToRun;

    private static Path pathrunToblock;

    private static Path pathblockTodevice;
    private static Path pathrunToReady;
    private static PathTransition runToEnd;
    private static PathTransition readyToRun;
    private static PathTransition blockTodevice;
    private static PathTransition runToReady;

    private static PathTransition runToBlock;
    private static Pane panerunToEnd;
    private static Pane panereadyToRun;

    private static Pane panerunToblock;

    private static Pane paneblockTodevice;
    private static Pane panerunToReady;
    public static Thread DispatherThread;
    //    运行时间
    private static volatile DoubleProperty runningtime;
    private static volatile double laststoptime;
    private static volatile double custarttime;

    public static ProcessDispatcher getInstance() {

        if (processDispatcher == null) {
            synchronized (ProcessDispatcher.class) {
                if (processDispatcher == null) {
                    processDispatcher = new ProcessDispatcher();
                }
            }
        }
        return processDispatcher;
    }

    static {
//        初始化
        runningtime = new SimpleDoubleProperty();
        laststoptime = 0.0;
        custarttime = 0.0;
        blockedProcessList = FXCollections.observableArrayList();
        readyProcessList = FXCollections.observableArrayList();
        endProcessList = FXCollections.observableArrayList();
        processHistoryList=FXCollections.observableArrayList();

        runToEnd = new PathTransition();
        readyToRun = new PathTransition();
        blockTodevice = new PathTransition();
        runToReady = new PathTransition();
        runToBlock =new PathTransition();
        //processRegister=new process();
        String[] end = new String[]{"end"};
//        初始化会创建一个闲逛进程
        hangOutProcess = Process.createProcess(end, "闲逛进程").getPcb();
        deviceList = DeviceDispatcher.deviceList;
    }

    // 调度进程
    public static void dispatchProcess() {
        //保留历史记录
//        创建线程
//        创建调度线程
        DispatherThread = new Thread() {
            public void run() {
//                循环
                while (true) {
//                    如果已经开始运行
                    if (isrunning) {
//                        如果CPU被唤醒
                        if (CPU.WakedUP) {
                            System.out.println("CPU状态是唤醒的");
//                            保存现场
                            System.out.println("保存上下文");
                            saveCPUprocessRegister();
//                            CPU.WakedUP=false;
//                            唤醒阻塞进程
                            System.out.println("唤醒阻塞进程");
                            awakeProcess();
                        }
//                        如果无中断或者CPU正常中断
                        if (CPU.PSW == CPU.NONE_INTERMIT || CPU.PSW == CPU.NORMAL_INTERMIT) {
////                            如果没有中断并且进程寄存器不为null
//                            if (CPU.PSW == CPU.NORMAL_INTERMIT && processRegister != null) {
////                                销毁进程，进程执行完毕
//                                destroyProcess();
//                                //scheduiUIController.updateUsage();
//                            }
//                            调度就绪进程
                            dispatchReadyProcess();
                            CPU.run();

                        }else if (CPU.PSW == CPU.TIME_INTERMIT) {
                            if (processRegister == null) {
                                CPU.PSW = 0;
                                CPU.run();
                            } else {
                                saveCPUprocessRegister();
                                try {
                                    Thread.sleep(500);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                                dispatchReadyProcess();
                                CPU.run();
                            }
                        }
                        else {
//                            如果执行寄存器为空
                            if (processRegister == null) {
                                CPU.PSW = CPU.NONE_INTERMIT;
                            } else {
//                                如果执行寄存器不为空
//                                占用设备，阻塞线程
                                blockPocess();
//                                调度就绪线程
                                dispatchReadyProcess();
                            }
//                            运行CPU
                            CPU.run();
                        }
                    }
                }
            }
        };
        DispatherThread.setDaemon(true);
        DispatherThread.start();

    }

    public static void timekeeping() {
        //创建时间记录线程
        Thread thread = new Thread() {
            public void run() {
                while (true) {
//                    如果正在运行，设置运行时间
                    if (isrunning) {
                        runningtime.set(laststoptime + System.currentTimeMillis() - custarttime);
                    }
                    try {
//                        循环沉睡
                        Thread.sleep(1L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread.setDaemon(true);
        thread.start();
    }

    //    唤醒进程
    public static void awakeProcess() {
//        如果有阻塞线程
        if (blockedProcessList.size() != 0) {
            int i = -1;
//            阻塞队列里找
            for (PCB pcb : blockedProcessList) {
//                如果阻塞队列中的线程IO完了，不占用设备了
                if (pcb.getHoldTime() == 0) {
//                    找到这个阻塞队列中pcb的索引给i
                    i = blockedProcessList.indexOf(pcb);
                    break;
                }
            }
//            如果i存在，说明这个线程阻塞时间到了
            if (i != -1) {
//                获取这个pcb
                PCB pcb = blockedProcessList.get(i);
                System.out.println("阻塞队列移除进程"+pcb.getName());
//                pc+1
                pcb.setPC(pcb.getPC() + 1);
//                阻塞队列移除这个pcb
                blockedProcessList.remove(pcb);
//                检查阻塞队列是否获得设备
                checkBlock(pcb.getTakeddevice());
//                设置cpu的寄存器
                processRegister = pcb;
                setCPURegister(processRegister);
//                设置未唤醒状态
                CPU.WakedUP = false;
                System.out.println("CPU设置未唤醒状态");
//                跑起来
                CPU.run();
            }
        }

        return;
    }

    //    销毁进程
    public static void destroyProcess() {
        //playrunToEnd();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(!endProcessList.contains(CPU.pcb)){
            endProcessList.add(CPU.pcb);
        }
        System.out.println("销毁"+CPU.pcb.getName());
        //进程运行完毕
        String runtime=String.valueOf(CPU.pcb.getRuntime());
        processHistoryList.add(new ProcessHistory(
                new SimpleDoubleProperty(runningtime.get()),
                new SimpleStringProperty("执行完毕"),
                new SimpleStringProperty(CPU.pcb.getName()),
                new SimpleStringProperty("执行时间:" + runtime),
                new SimpleStringProperty(CPU.pcb.getResult())
        ));

        MemoryDispatcher.freePCB(processRegister);
        MemoryDispatcher.freeRecordBlock(processRegister);
        showresources();
        updateUI();
    }

    public static void dispatchReadyProcess() {
//        如果还有就绪进程
        if (readyProcessList.size() != 0) {
            playreadyToRun();
//            移除排队的第一个就绪进程，加载为processRegister调度它执行
            processRegister = readyProcessList.remove(0);
//            加载CPU寄存器
            setCPURegister(processRegister);
        } else {
//            没有就绪进程了
            processRegister = null;
            setCPURegister(hangOutProcess);
        }

    }

    //    保存线程现场
    public static void saveCPUprocessRegister() {
        if (processRegister != null) {
//            更新进程寄存器
            processRegister = CPU.pcb;
//            运行到就绪  小球移动
            playrunToReady();
//            停了一秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
//            加入到就绪进程list
            readyProcessList.add(processRegister);

            // 添加历史记录
            processHistoryList.add(new ProcessHistory(
                    new SimpleDoubleProperty(runningtime.get()),
                    new SimpleStringProperty("就绪"),
                    new SimpleStringProperty(CPU.pcb.getName()),
                    new SimpleStringProperty("阻塞队列->就绪队列"),
                    new SimpleStringProperty("NULL")
            ));
        }
    }

    //    阻塞进程
    public static void blockPocess() {
//        cpu PCB赋值给程序寄存器
        processRegister = CPU.pcb;
//        将该PCB添加到阻塞队列
        blockedProcessList.add(processRegister);
//        占用设备

        // 添加历史记录
        processHistoryList.add(new ProcessHistory(
                new SimpleDoubleProperty(runningtime.get()),
                new SimpleStringProperty("阻塞"),
                new SimpleStringProperty(CPU.pcb.getName()),
                new SimpleStringProperty("正在运行->阻塞队列"),
                new SimpleStringProperty("请求设备:"+String.valueOf(CPU.pcb.getNeeddevice()))
        ));
        takeDevice(processRegister);
    }

    //检查阻塞队列是否获得设备
    public static void checkBlock(Character devicename) {
//        如果阻塞队列有线程
        if (blockedProcessList.size() != 0) {
//            遍历阻塞PCB
            for (PCB pcb : blockedProcessList) {
//                如果pcb需要的设备是这个devicename设备，并且当前pcb不占用设备
//                说明这个pcb是之前想要占用设备但是已经没设备了，进入的阻塞队列
                if (pcb.getNeeddevice().equals(devicename) && pcb.getTakeddevice() == 'x') {
//                    检查PCB需要的设备是否被占用
                    if (DeviceDispatcher.checkEquipment(pcb.getNeeddevice())) {
                        //检查设备是否确实被占用，也就是空闲
//                        没被占用
                        showresources();
//                        设置PCB占用这个设备
                        pcb.setTakeddevice(devicename.charValue());
                        // playblockTodevice();
                        DeviceDispatcher.requestDevice(pcb, pcb.getNeeddevice(), pcb.getHoldTime());
                    }
                }
            }
        }
    }

    public static void takeDevice(PCB pcb) {
        String Instruction = MemoryDispatcher.fetchInstruction(pcb.getPC());
        System.out.println("线程"+pcb.getName()+"占用设备指令--->"+Instruction);
        if (DeviceDispatcher.checkEquipment(Instruction.charAt(1))) {
            showresources();
//            pcb设置占用的设备
            pcb.setTakeddevice(Instruction.charAt(1));

            playblockTodevice();
            playrunToBlock();
//            去请求占用这个设备
            DeviceDispatcher.requestDevice(pcb, Instruction.charAt(1), Instruction.charAt(2) - '0');
        }

    }

    public static void updateUI() {
        Platform.runLater(new Runnable() {
            public void run() {
                //这个函数重写，展示
                MemoryDispatcher.updateUI();
            }
        });
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //    CPU寄存器加载pcb的上下文
    public static void setCPURegister(PCB p) {
//        设置PC
        CPU.PC = p.getPC();
//        PSW
        CPU.PSW = CPU.NONE_INTERMIT;
//        PCB
        CPU.pcb = p;
    }

    //    前端展示资源
    public static void showresources() {
//        控制台前端展示，在JavaFX Application线程空闲时运行
        Platform.runLater(new Runnable() {
            public void run() {
                scheduiUIController.getMemoryUsage().setText(
//                        内存占用，每个PCB的每条指令占1
                        String.valueOf(Memory.getMemoryUsage()) + "/512字节");
                scheduiUIController.getProcessUsage().setText(
//                        PCB个数
                        String.valueOf(Memory.getPCBlistSize() + "/10个PCB"));
                scheduiUIController.getDeviceUsage().setText(
//                        闲置设备个数
                        String.valueOf(DeviceDispatcher.getFreeDeviceNum()) + "/8台设备");
            }
        });
    }

    //    暂停线程运行
    public static void stop() {
        isrunning = false;
        laststoptime = runningtime.get();
    }

    //    运行
    public static void play() {
        isrunning = true;
//        设置当前启动时间
        custarttime = System.currentTimeMillis();
    }

    public static void setPanerunToEnd(Pane panerunToEnd1) {
        panerunToEnd = panerunToEnd1;
    }

    public static void setPanerunToblock(Pane panerunToblock1){panerunToblock=panerunToblock1;}
    public static void setPanereadyToRun(Pane panereadyToRun1) {
        panereadyToRun = panereadyToRun1;
    }

    public static void setPaneblockTodevice(Pane paneblockTodevice1) {
        paneblockTodevice = paneblockTodevice1;
    }

    public static void setPanedeviceToReady(Pane panerunToReady1) {
        panerunToReady = panerunToReady1;
    }

    public void setReadyTableView(TableView<PCB> tableView, TableColumn<PCB, StringProperty> Readyname, TableColumn<PCB, DoubleProperty> ReadyRt, TableColumn<PCB, DoubleProperty> ReadyRestTime, TableColumn<PCB, IntegerProperty> Readylength, TableColumn<PCB, Double> processBar) {
        Readyname.setCellValueFactory(new PropertyValueFactory<>("name"));
        ReadyRt.setCellValueFactory(new PropertyValueFactory<>("runtime"));
        ReadyRestTime.setCellValueFactory(new PropertyValueFactory<>("resttime"));
        Readylength.setCellValueFactory(new PropertyValueFactory<>("length"));
        processBar.setCellValueFactory(new PropertyValueFactory<>("progress"));
        processBar.setCellFactory(ProgressBarTableCell.forTableColumn());
        tableView.setItems(this.readyProcessList);
    }

    public void setBlockedTableView(TableView<PCB> BlockedProcess, TableColumn<PCB, StringProperty> BlockedName, TableColumn<PCB, Character> BlockedDeviceType, TableColumn<PCB, IntegerProperty> BlockeddeviceTime, TableColumn<PCB, DoubleProperty> BlockedTRT, TableColumn<PCB, DoubleProperty> BlockedRRT) {
        BlockedName.setCellValueFactory(new PropertyValueFactory<>("name"));
        BlockedTRT.setCellValueFactory(new PropertyValueFactory<>("runtime"));
        BlockedRRT.setCellValueFactory(new PropertyValueFactory<>("resttime"));
        BlockedDeviceType.setCellValueFactory(new PropertyValueFactory<>("needdevice"));
        BlockeddeviceTime.setCellValueFactory(new PropertyValueFactory<>("holdTime"));
        BlockedProcess.setItems(this.blockedProcessList);

    }

    public void setEndTableView(TableView<PCB> EndedTable, TableColumn<PCB, DoubleProperty> endedRT, TableColumn<PCB, StringProperty> endedName, TableColumn<PCB, StringProperty> endedresult) {
        endedName.setCellValueFactory(new PropertyValueFactory<>("name"));
        endedRT.setCellValueFactory(new PropertyValueFactory<>("runtime"));
        endedresult.setCellValueFactory(new PropertyValueFactory<>("result"));
        EndedTable.setItems(this.endProcessList);

    }

    public void setDeviceTableView(TableView<Device> DeviceTable, TableColumn<Device, Character> device, TableColumn<Device, StringProperty> DevicePName, TableColumn<Device, IntegerProperty> DeviceRT) {
        device.setCellValueFactory(new PropertyValueFactory<>("name"));
        DevicePName.setCellValueFactory(new PropertyValueFactory<>("process"));
        DeviceRT.setCellValueFactory(new PropertyValueFactory<>("occupiedTime"));
        DeviceTable.setItems(DeviceDispatcher.deviceList);

        System.out.println("DeviceTable refresh");
    }


    public void setHistoryTableView(TableView<ProcessHistory>ProcessHistoryTable,
                                    TableColumn<ProcessHistory, StringProperty>Result,
                                    TableColumn<ProcessHistory, StringProperty> Operation,
                                    TableColumn<ProcessHistory, StringProperty> Status,
                                    TableColumn<ProcessHistory, StringProperty> Process,
                                    TableColumn<ProcessHistory, DoubleProperty> Time)
    {
        Result.setCellValueFactory(new PropertyValueFactory<>("result"));
        Operation.setCellValueFactory(new PropertyValueFactory<>("operation"));
        Status.setCellValueFactory(new PropertyValueFactory<>("status"));
        Process.setCellValueFactory(new PropertyValueFactory<>("process"));
        Time.setCellValueFactory(new PropertyValueFactory<>("Time"));
        ProcessHistoryTable.setItems(this.processHistoryList);
    }

    public static ObservableList<ProcessHistory> getProcessHistoryList() {
        return processHistoryList;
    }

    public static void setPathrunToEnd(Path pathrunToEnd1) {
        pathrunToEnd = pathrunToEnd1;
        runToEnd.setPath(pathrunToEnd);
        runToEnd.setCycleCount(1);
        runToEnd.setDuration(Duration.seconds(0.5));
    }

    public static void setPathreadyToRun(Path pathreadyToRun1) {
        pathreadyToRun = pathreadyToRun1;
        readyToRun.setPath(pathreadyToRun);
        readyToRun.setCycleCount(1);
        readyToRun.setDuration(Duration.seconds(1));
    }

    public static void setPathRunToBlock(Path pathrunToblock1){
        pathrunToblock=pathrunToblock1;
        runToBlock.setPath(pathrunToblock);
        runToBlock.setCycleCount(1);
        runToBlock.setDuration(Duration.seconds(1));
    }
    public static void setPathblockTodevice(Path pathblockTodevice1) {
        pathblockTodevice = pathblockTodevice1;
        blockTodevice.setPath(pathblockTodevice);
        blockTodevice.setCycleCount(1);
        blockTodevice.setDuration(Duration.seconds(1));
    }

    public static void setPathrunToReady(Path pathrunToReady1) {
        pathrunToReady = pathrunToReady1;
        runToReady.setPath(pathrunToReady);
        runToReady.setCycleCount(1);
        runToReady.setDuration(Duration.seconds(1));
    }

    public static void playrunToEnd() {//队列之间的小球转移
        final Rectangle R = new Rectangle(20, 20);
        R.setFill(Paint.valueOf("#48D1CC"));
        (new Thread(new Runnable() {
            public void run() {
                Platform.runLater(new Runnable() {
                    public void run() {
                        panerunToEnd.getChildren().add(R);
                    }
                });
            }
        })).start();
        runToEnd.setNode(R);
        runToEnd.play();
        (new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(500L);
                } catch (InterruptedException ex) {
                    Logger.getLogger(ProcessDispatcher.class.getName()).log(Level.SEVERE, (String) null, ex);
                }
                Platform.runLater(new Runnable() {
                    public void run() {
                        panerunToEnd.getChildren().remove(R);
                    }
                });
            }
        })).start();
    }

    public static void playrunToBlock(){
        final Rectangle R = new Rectangle(20, 20);
        R.setFill(Paint.valueOf("#48D1CC"));
        (new Thread(new Runnable() {
            public void run() {
                Platform.runLater(new Runnable() {
                    public void run() {
                        panerunToblock.getChildren().add(R);
                    }
                });
            }
        })).start();
        runToBlock.setNode(R);
        runToBlock.play();
        (new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(500L);
                } catch (InterruptedException ex) {
                    Logger.getLogger(ProcessDispatcher.class.getName()).log(Level.SEVERE, (String) null, ex);
                }
                Platform.runLater(new Runnable() {
                    public void run() {
                        panerunToblock.getChildren().remove(R);
                    }
                });
            }
        })).start();
    }

    //    就绪到运行框框的小球转移
    public static void playreadyToRun() {//队列之间的小球转移
        final Rectangle R = new Rectangle(20, 20);
        R.setFill(Paint.valueOf("#FFA500"));
        (new Thread(new Runnable() {
            public void run() {
                Platform.runLater(new Runnable() {
                    public void run() {
                        panereadyToRun.getChildren().add(R);
                    }
                });
            }
        })).start();

        readyToRun.setNode(R);
        readyToRun.play();
        (new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException ex) {
                    Logger.getLogger(ProcessDispatcher.class.getName()).log(Level.SEVERE, (String) null, ex);
                }
                Platform.runLater(new Runnable() {
                    public void run() {
                        panereadyToRun.getChildren().remove(R);
                    }
                });
            }
        })).start();
    }

    public static void playblockTodevice() {//队列之间的小球转移
        final Rectangle R = new Rectangle(20, 20);
        R.setFill(Paint.valueOf("#FF6347"));
        (new Thread(new Runnable() {
            public void run() {
                Platform.runLater(new Runnable() {
                    public void run() {
                        paneblockTodevice.getChildren().add(R);
                    }
                });
            }
        })).start();
        blockTodevice.setNode(R);
        blockTodevice.play();
        (new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException ex) {
                    Logger.getLogger(ProcessDispatcher.class.getName()).log(Level.SEVERE, (String) null, ex);
                }
                Platform.runLater(new Runnable() {
                    public void run() {
                        paneblockTodevice.getChildren().remove(R);
                    }
                });
            }
        })).start();
    }

    //    运行到就绪
    public static void playrunToReady() {//队列之间的小球转移
        final Rectangle R = new Rectangle(20, 20);
        R.setFill(Paint.valueOf("#48D1CC"));
        (new Thread(new Runnable() {
            public void run() {
                Platform.runLater(new Runnable() {
                    public void run() {
                        panerunToReady.getChildren().add(R);
                    }
                });
            }
        })).start();
        runToReady.setNode(R);
        runToReady.play();
        (new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException ex) {
                    Logger.getLogger(ProcessDispatcher.class.getName()).log(Level.SEVERE, (String) null, ex);
                }
                Platform.runLater(new Runnable() {
                    public void run() {
                        panerunToReady.getChildren().remove(R);
                    }
                });
            }
        })).start();
    }

    public static ObservableList<PCB> getReadyProcessList() {
        return readyProcessList;
    }

    public static void setReadyProcessList(ObservableList<PCB> readyProcessList) {
        ProcessDispatcher.readyProcessList = readyProcessList;
    }

    public static ObservableList<PCB> getBlockedProcessList() {
        return blockedProcessList;
    }

    public static ObservableList<Device> getDeviceList() {
        return deviceList;
    }

    public static void setDeviceList(ObservableList<Device> deviceList) {
        ProcessDispatcher.deviceList = deviceList;
    }

    public static double getRunningtime() {
        return runningtime.get();
    }


}